home *** CD-ROM | disk | FTP | other *** search
/ BBS Toolkit / BBS Toolkit.iso / doors_1 / fd200.zip / AVL_TREE.PAS next >
Pascal/Delphi Source File  |  1988-02-27  |  13KB  |  436 lines

  1. type  balance = ( L, B, R );
  2.  
  3.       LINK = ^Branch;
  4.  
  5.       Branch  = record
  6.                  leaf     : data;
  7.                  left     : LINK;
  8.                  right    : LINK;
  9.                  bal      : balance;
  10.                 end;
  11.  
  12.  
  13. { ***********   CONSTANTS, AND VARIABLES FOR AV Lists ********** }
  14.  
  15. const on_bit  : array[0..15] of word =
  16.                 ( $0001,$0002,$0004,$0008,$0010,$0020,$0040,$0080,
  17.                   $0100,$0200,$0400,$0800,$1000,$2000,$4000,$8000 );
  18.       off_bit : array[0..15] of word =
  19.                 ( $FFFE,$FFFD,$FFFB,$FFF7,$FFEF,$FFDF,$FFBF,$FF7F,
  20.                   $FEFF,$FDFF,$FBFF,$F7FF,$EFFF,$DFFF,$BFFF,$7FFF );
  21.       depth : integer = -1;
  22.       h     : integer = 0;      { Set by recursive calls to search to
  23.                                indicate that the tree has grown.
  24.                                It will magically change its value
  25.                                everytime ins() is called recursively. }
  26.  
  27. var  Newnode,
  28.      Conflicting,
  29.      AvlKey,
  30.      root,
  31.      tbranch,
  32.      p            : LINK;
  33.      Notfound     : boolean;
  34.      map : array[0..1023] of integer;
  35.      n,i : integer;
  36.      
  37.  
  38.  
  39. { ***********   SPECIFIC PROCEDURES AND FUNCTION FOR AV Lists ********** }
  40.  
  41. function talloc: LINK;
  42. var p : LINK;
  43. begin
  44.   New(p);
  45.   if p <> NIL then
  46.     with p^ do
  47.     begin
  48.       left := NIL;
  49.       right := NIL;
  50.       bal   := B;
  51.     end;
  52.   talloc := p;
  53. end;
  54.  
  55. procedure tfree( var p : LINK);
  56. begin
  57.   dispose(p);
  58. end;
  59.  
  60. function testbit(c: integer): integer;
  61. begin
  62.  testbit := Map[ c SHR 4] AND (on_bit[c AND $0F]);
  63. end;
  64.  
  65. procedure  setbit( c, val : integer);
  66. begin
  67.    if (val <> 0)
  68.    then
  69.       Map[c SHR 4] := Map[c SHR 4] OR (on_bit[(c AND $0F)])
  70.    else
  71.       Map[c SHR 4] := Map[c SHR 4] AND (off_bit[(c AND $0F)]) ;
  72. end;
  73.  
  74. procedure trav(root : LINK; direction: balance; device : integer);
  75. label trav_exit;
  76. var i : integer;
  77. begin
  78.    if (root <> NIL) AND (escape = FALSE) then
  79.    begin
  80.      depth := depth + 1;
  81.      if (root^.left <> NIL)
  82.        then trav(root^.left,R, device)
  83.        else setbit(depth + 1,1);
  84.      if (escape = TRUE) then goto trav_exit;
  85.      if device = 0 then print(root^.leaf)
  86.                    else fprint(root^.leaf);
  87.      if direction = L then setbit(depth, 0)
  88.                       else setbit(depth, 1);
  89.      if (root^.right <> NIL)
  90.      then  trav(root^.right, L, device)
  91.      else  setbit(depth + 1, 0);
  92.      depth := depth - 1;
  93.    end;
  94. trav_exit:
  95. end;
  96.  
  97. procedure tprint(root : LINK);
  98. var i : integer;
  99. begin
  100.    escape := FALSE;
  101.    for i := 0 to 1023 do map[i] := 0;
  102.    depth := -1;
  103.    trav( root, R, 0);
  104. end;
  105.  
  106. function find( root, key : LINK ): LINK;
  107. begin
  108.    if ( root = NIL )
  109.      then  find := NIL
  110.      else  case cmp( key^.leaf, root^.leaf) of
  111.              -1 : find := find(root^.left, key);
  112.               0 : find := root;
  113.               1 : find := find(root^.right, key);
  114.            end;
  115. end;
  116.  
  117. procedure ins( var pp : LINK );
  118. var  p, p1, p2 : LINK;
  119. begin
  120.    p := pp;
  121.    if ( p = NIL )
  122.    then
  123.      begin
  124.         p := Newnode;
  125.         h := 1;
  126.      end
  127.    else
  128.      case cmp(newnode^.leaf, p^.leaf) of
  129.         0 : Conflicting := p;
  130.        -1 : begin
  131.               ins( p^.left );
  132.               if ( h > 0 ) then
  133.               case p^.bal of
  134.                  R: begin
  135.                       p^.bal := B;
  136.                       h := 0;
  137.                     end;
  138.                  B: p^.bal := L;
  139.                  L: begin
  140.                       p1 := p^.left;
  141.                       if ( p1^.bal = L )
  142.                       then begin
  143.                              p^.left   := p1^.right;
  144.                              p1^.right := p;
  145.                              p^.bal    := B;
  146.                              p         := p1;
  147.                            end
  148.                       else begin
  149.                              p2          := p1^.right;
  150.                              p1^.right   := p2^.left;
  151.                              p2^.left    := p1;
  152.                              p^.left     := p2^.right;
  153.                              p2^.right   := p;
  154.                              if (p2^.bal = L)
  155.                                then p^.bal := R
  156.                                else p^.bal := B;
  157.                              if (p2^.bal = R)
  158.                                then p1^.bal := L
  159.                                else p1^.bal := B;
  160.                              p := p2;
  161.                            end;
  162.                       p^.bal := B;
  163.                       h      := 0;
  164.                     end;
  165.               end;
  166.             end;
  167.         1 : begin
  168.               ins( p^.right );
  169.               if ( h > 0 ) then
  170.               case  p^.bal  of
  171.                 L: begin
  172.                      p^.bal := B;
  173.                      h := 0;
  174.                    end;
  175.                 B: p^.bal := R;
  176.                 R: begin
  177.                      p1 := p^.right;
  178.                      if ( p1^.bal = R )
  179.                      then
  180.                        begin
  181.                          p^.right := p1^.left;
  182.                          p1^.left := p;
  183.                          p^.bal   := B;
  184.                          p        := p1;
  185.                        end
  186.                      else
  187.                        begin
  188.                          p2        := p1^.left;
  189.                          p1^.left  := p2^.right;
  190.                          p2^.right := p1;
  191.                          p^.right  := p2^.left;
  192.                          p2^.left  := p;
  193.                          if (p2^.bal = R)
  194.                            then p^.bal := L
  195.                            else p^.bal := B;
  196.                          if (p2^.bal = L)
  197.                            then p1^.bal := R
  198.                            else p1^.bal := B;
  199.                          p           := p2;
  200.                        end;
  201.                     p^.bal := B;
  202.                     h      := 0;
  203.                   end;
  204.               end;
  205.             end;
  206.      end;
  207.      pp := p;
  208. end;
  209.  
  210. procedure insert( var rootp, netbrnch : LINK);
  211. begin
  212. { Insert newnode into tree pointed to by rootp.  Cmp is passed
  213.   Return NIL on success or a pointer to the conflicting node
  214.   on error.
  215. }
  216.    h := 0;
  217.    Newnode := netbrnch;
  218.    Conflicting := NIL;
  219.    ins(rootp);
  220.    if Conflicting <> NIL then tfree(netbrnch);
  221. end;
  222.  
  223. function balance_l( var pp : LINK ): boolean;
  224.  
  225. { This routine is called when the left branch of the current
  226.   subtree (pointed to by p) has shrunk.  It adjusts the balance
  227.   factors and rebalances if necessary, modifying *pp to point
  228.   at the new root (after the rebalance).  Returns TRUE if the
  229.   tree got smaller as a result of the delete or the rebalance
  230.   operation, else returns 0.
  231. }
  232. var p, p1, p2 : LINK;
  233.     b1, b2    : balance;
  234.     got_smaller : boolean;
  235.  
  236. begin
  237.   got_smaller := TRUE;
  238.   p := pp;
  239.   case p^.bal of
  240.     L: p^.bal := B;
  241.     B: begin
  242.          p^.bal := R;
  243.          got_smaller := FALSE;
  244.        end;
  245.     R: begin
  246.          p1 := p^.right;
  247.          b1 := p1^.bal;
  248.          if ( b1 <> L )
  249.          then begin
  250.                 p^.right := p1^.left;
  251.                 p1^.left := p;
  252.                 if ( b1 <> B )
  253.                 then begin
  254.                        p^.bal := B;
  255.                        p1^.bal := B;
  256.                      end
  257.                 else begin
  258.                        p^.bal := R;
  259.                        p1^.bal := L;
  260.                        got_smaller := FALSE;
  261.                      end;
  262.                 p := p1;
  263.               end
  264.             else begin
  265.                    p2         := p1^.left;
  266.                    b2         := p2^.bal;
  267.                    p1^.left   := p2^.right;
  268.                    p2^.right  := p1;
  269.                    p^.right   := p2^.left;
  270.                    p2^.left   := p;
  271.                    case b2 of
  272.                      R    : p^.bal := L;
  273.                      B, L : p^.bal := B;
  274.                    end;
  275.                    case b2 of
  276.                      L    : p1^.bal := R;
  277.                      B, R : p1^.bal := B;
  278.                    end;
  279.                    p           := p2;
  280.                    p2^.bal     := B;
  281.                  end;
  282.        end;
  283.    end;
  284.    pp := p;
  285.    balance_l := got_smaller;
  286. end;
  287.  
  288.  
  289. function balance_r( var pp : LINK ): boolean;
  290. { same as balance_l, but is called when a right subtree has
  291.   been made smaller.
  292. }
  293. var p, p1, p2 : LINK;
  294.    b1, b2     : balance;
  295.    got_smaller : boolean;
  296. begin
  297.   got_smaller := TRUE;
  298.   p := pp;
  299.   case p^.bal of
  300.     R: p^.bal := B;
  301.     B: begin
  302.          p^.bal := L;
  303.          got_smaller := FALSE;
  304.        end;
  305.     L: begin
  306.          p1 := p^.left;
  307.          b1 := p1^.bal;
  308.          if ( b1 <> R )
  309.          then begin
  310.                 p^.left     := p1^.right;
  311.                 p1^.right   := p;
  312.                 if ( b1 <> B )
  313.                 then p^.bal := B
  314.                 else begin
  315.                        p^.bal      := L;
  316.                        p1^.bal     := R;
  317.                        got_smaller := FALSE;
  318.                      end;
  319.                 p := p1;
  320.               end
  321.          else begin
  322.                 p2          := p1^.right;
  323.                 b2          := p2^.bal;
  324.                 p1^.right   := p2^.left;
  325.                 p2^.left    := p1;
  326.                 p^.left     := p2^.right;
  327.                 p2^.right   := p;
  328.                 case b2 of
  329.                   L   : p^.bal := R;
  330.                   B,R : p^.bal := B;
  331.                 end;
  332.                 case b2 of
  333.                   R   : p1^.bal := L;
  334.                   B,L : p1^.bal := R;
  335.                 end;
  336.                 p           := p2;
  337.                 p2^.bal     := B;
  338.               end;
  339.        end;
  340.   end;
  341.   pp := p;
  342.   balance_r := got_smaller;
  343. end;
  344.  
  345. function descend( var  rootp, dpp : LINK): boolean;
  346. { rootp     address of root of current node
  347.   dpp       address of node to be deleted
  348.  
  349.   Does the actual delete when the root node has both left and
  350.   right descendents.  Descends to the rightmost node of the left
  351.   subtree and then copies the contents of that node to the
  352.   node-to-be-deleted (dpp).  Then the node-to-be-deleted is
  353.   modified to point to the former rightmost node.
  354. }
  355. begin
  356.   if ( rootp^.right <> NIL )
  357.   then
  358.     case descend( rootp^.right, dpp) of
  359.       FALSE  : descend := FALSE;
  360.       TRUE   : descend := balance_r(rootp) ;
  361.     end
  362.   else begin
  363.          move(rootp^.leaf,dpp^.leaf,sizeof(data));
  364.          dpp := rootp;
  365.          rootp := rootp^.left;
  366.          descend := TRUE;
  367.        end;
  368. end;
  369.  
  370. function del(var  rootp : LINK ): boolean;
  371. {
  372.   Delete AvlKey from tree pointed to by rootp.  Return TRUE if the size
  373.   of the tree has been reduced, FALSE otherwise.
  374. }
  375. var  dp : LINK;      { pointer to node to delete }
  376.      got_smaller : boolean;
  377. begin
  378.    got_smaller := FALSE;  { set TRUE if tree shrinks  }
  379.    if ( rootp = NIL )
  380.    then Notfound := TRUE
  381.    else begin
  382.           case cmp(AvlKey^.leaf, rootp^.leaf) of
  383.             -1 : if ( del(rootp^.left) = TRUE )
  384.                  then got_smaller := balance_l( rootp ) ;
  385.              1 : if ( del(rootp^.right) = TRUE )
  386.                  then got_smaller := balance_r( rootp ) ;
  387.              0 : begin
  388.                    case check_if_ok(rootp^.leaf) of
  389.                      -1 : Notfound := TRUE;
  390.                       0 : if (del(rootp^.right) = TRUE)
  391.                           then got_smaller := balance_r(rootp);
  392.                       1 : begin
  393.                             dp := rootp;
  394.                             if ( dp^.right = NIL )
  395.                             then begin
  396.                                    rootp      := dp^.left;
  397.                                    got_smaller := TRUE;
  398.                                  end
  399.                             else if ( dp^.left = NIL )
  400.                                  then begin
  401.                                         rootp := dp^.right;
  402.                                         got_smaller := TRUE;
  403.                                       end
  404.                                  else if ( descend(rootp^.left, dp ) = TRUE )
  405.                                       then got_smaller := balance_l( rootp ) ;
  406.                             tfree( dp );
  407.                           end;
  408.                    end;
  409.                  end;
  410.            end;
  411.          end;
  412.   del := got_smaller;
  413. end;
  414.  
  415.  
  416. function  delete( var rootp, pass : LINK ): boolean;
  417. var dmy : boolean;
  418. {
  419.   Cmp is a comparison routine with two leaf records passed to
  420.   it.  It should return
  421.  
  422.        -1 if key < node;
  423.         0 if key = node;
  424.         1 if key > node.
  425.  
  426.   DELETE returns 1 if the node was deleted,
  427.                  0 if the node wasn't in the tree.
  428. }
  429. begin
  430.   AvlKey := pass;
  431.   Notfound := FALSE;
  432.   dmy :=  del( rootp );
  433.   delete := NOT Notfound;
  434. end;
  435.  
  436.